home *** CD-ROM | disk | FTP | other *** search
Wrap
/* File: MouseModule.c Contains: HID Module for USB Mouse Version: xxx put version here xxx Copyright: © 1997-1999 by Apple Computer, Inc., all rights reserved. */ /* Notes to developers: 1. The WatchDog functionality is *NOT* needed in your drivers. It is part of an experiment to determine if IntReads are ever dropped on the floor. It was left in (but disabled) and checked into the projector database so that the coding effort wasn't lost. We do not believe that IntReads are lost, so your drivers should not need this WatchDog functionality. 2. Apple reserves the right to do the following: Release Mouse or Keyboard drivers that are vendor specific for Apple products Release said mouse or keyboard drivers in binary form (but not necessarily in source form) Prevent 3rd parties from writing generic drivers */ #include <DriverServices.h> #include <Devices.h> #include <LowMem.h> #include <MacTypes.h> #include <Processes.h> #include <USB.h> #include "MouseModule.h" enum{ kCheckEvery = 10000, kFastCheck = 1000 }; #define EnableWatchDog 0 #define EnableRemoteWakeup 0 usbMousePBStruct myMousePB; usbMousePBStruct watchDogPB; void InitParamBlock(USBReference theInterfaceRef, USBPB * paramblock) { paramblock->usbReference = theInterfaceRef; paramblock->pbVersion = kUSBCurrentPBVersion; paramblock->usb.cntl.WIndex = 0; paramblock->usb.cntl.WValue = 0; paramblock->usbBuffer = nil; paramblock->usbActCount = 0; paramblock->usbReqCount = 0; paramblock->usbFlags = 0; paramblock->usbOther = 0; paramblock->usbStatus = noErr; } Boolean immediateError(OSStatus err) { return((err != kUSBPending) && (err != noErr) ); } void MouseInitiateTransaction(USBPB *pb) { usbMousePBStruct *pMousePB; OSStatus myErr; pMousePB = (usbMousePBStruct *)(pb); pMousePB->transDepth++; if (pMousePB->transDepth < 0) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth < 0 (initiation)", pMousePB->pb.usbRefcon ); } if (pMousePB->transDepth > 1) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth > 1 (initiation)", pMousePB->pb.usbRefcon ); } if (pMousePB->driverRemovalPending) { pMousePB->pb.usbRefcon = kReturnFromDriver; return; } switch(pMousePB->pb.usbRefcon & ~kRetryTransaction) { case kConfigureInterface: InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb); pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc; pMousePB->pb.usbRefcon |= kCompletionPending; myErr = USBConfigureInterface( &pMousePB->pb ); if(immediateError(myErr)) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kConfigureInterface - immediate error", myErr); pMousePB->pb.usbRefcon = kReturnFromDriver; } break; case kSetProtocol: InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb); pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface); pMousePB->pb.usb.cntl.BRequest = kHIDRqSetProtocol; pMousePB->pb.usb.cntl.WValue = kHIDBootProtocolValue; pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber; pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc; pMousePB->pb.usbRefcon |= kCompletionPending; myErr = USBDeviceRequest(&pMousePB->pb); if (immediateError(myErr)) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kSetProtocol - immediate error", myErr); } break; case kSetIdleRequest: USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Do a SetIdle on non-Apple mice, as some 3rd party mice don't send reports on button up", pMousePB->pipeRef); InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb); pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface); pMousePB->pb.usb.cntl.BRequest = kHIDRqSetIdle; pMousePB->pb.usb.cntl.WValue = ((24/4)<<8); // force a read completion if idle for more than 24ms pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber; pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc; pMousePB->pb.usbRefcon |= kCompletionPending; myErr = USBDeviceRequest(&pMousePB->pb); if(immediateError(myErr)) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kSetIdleRequest - immediate error", myErr); } break; #if EnableRemoteWakeup case kSetRemoteWakeup: USBExpertStatusLevel(3, pMousePB->interfaceRef, kMouseModuleName": Set remote wakeup for mouse", pMousePB->pipeRef); InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb); pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBDevice); pMousePB->pb.usb.cntl.BRequest = kUSBRqSetFeature; pMousePB->pb.usb.cntl.WValue = kUSBFeatureDeviceRemoteWakeup; pMousePB->pb.usb.cntl.WIndex = 0; pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc; pMousePB->pb.usbRefcon |= kCompletionPending; myErr = USBDeviceRequest(&pMousePB->pb); if(immediateError(myErr)) { USBExpertFatalError(pMousePB->interfaceRef, myErr, kMouseModuleName": set remote wakeup request - immediate error", myErr); } break; #endif case kFindPipe: InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb); pMousePB->pb.usbFlags = kUSBIn; pMousePB->pb.usbClassType = kUSBInterrupt; pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc; pMousePB->pb.usbRefcon |= kCompletionPending; myErr = USBFindNextPipe( &pMousePB->pb ); if((immediateError(myErr)) || (pMousePB->pb.usbBuffer == nil)) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kFindPipe - immediate error", myErr); pMousePB->pb.usbRefcon = kReturnFromDriver; } break; case kReadInterruptPipe: InitParamBlock(pMousePB->pipeRef, &pMousePB->pb); pMousePB->pb.usbBuffer = (Ptr)pMousePB->hidReport; pMousePB->pb.usbReqCount = pMousePB->maxPacketSize; pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber; pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc; pMousePB->pb.usbRefcon |= kCompletionPending; #ifndef DDKBuild pMousePB->pb.usbFlags |= kUSBDebugAwareFlag; #endif myErr = USBIntRead(&pMousePB->pb); if(immediateError(myErr)) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Read Interrupt Pipe (ImmediateError)", myErr); } break; case kResetMouse: InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb); pMousePB->pb.usbRefcon |= kCompletionPending; pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc; myErr = USBResetDevice( &pMousePB->pb ); if(myErr == kUSBDeviceBusy) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": reset busy, backing off", myErr); pMousePB->pb.usbReqCount = 100; pMousePB->pb.usbRefcon = kResetMouseDelay | kCompletionPending; USBDelay( &pMousePB->pb ); } else if(immediateError(myErr)) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kResetMouse - immediate error", myErr); pMousePB->pb.usbRefcon = kReturnFromDriver; } break; case kGetPortStatus: InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb); pMousePB->pb.usbRefcon |= kCompletionPending; myErr = USBPortStatus( &pMousePB->pb ); if(myErr == kUSBDeviceBusy) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": status busy, backing off", myErr); pMousePB->pb.usbReqCount = 100; pMousePB->pb.usbRefcon = kPortStatusDelay | kCompletionPending; USBDelay( &pMousePB->pb ); } else if(immediateError(myErr)) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kGetPortStatus - immediate error", myErr); pMousePB->pb.usbRefcon = kReturnFromDriver; } break; default: USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Transaction initiated with bad refcon value", pMousePB->pb.usbRefcon); pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver; break; } // At this point the control is returned to the system. If a USB transaction // has been initiated, then it will call the Complete procs // (below) to handle the results of the transaction. } void WatchDogCompletionProc(USBPB *pb) { usbMousePBStruct *pWatchDogPB; OSStatus myErr; UInt32 delayTime = 0; pWatchDogPB = (usbMousePBStruct *)(pb); if (!pWatchDogPB->driverRemovalPending) { delayTime = 50; // come back in 50ms if we're currently processing a completion callback if (myMousePB.pb.usbRefcon & kCompletionInProgess) { USBExpertStatusLevel(5, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog occurred while processing a completion callback (check again in 50ms)", myMousePB.pb.usbRefcon); } else { switch(pWatchDogPB->watchDogState) { case kDelay10Seconds: if (pWatchDogPB->watchDogActivityFlag) { USBExpertStatusLevel(5, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog - Mouse activity detected", pWatchDogPB->watchDogState); delayTime = kCheckEvery; pWatchDogPB->watchDogAbortFlag = false; } else { USBExpertStatusLevel(5, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog - No mouse activity detected, aborting pipe", pWatchDogPB->watchDogState); delayTime = kFastCheck; pWatchDogPB->watchDogState = kCheckForAbort; } break; case kCheckForAbort: delayTime = kCheckEvery; pWatchDogPB->watchDogState = kDelay10Seconds; if (pWatchDogPB->watchDogAbortFlag) { USBExpertStatusLevel(5, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog - Abort detected in completion routine", pWatchDogPB->watchDogState); } else { USBExpertStatusLevel(4, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog - No abort detected, restarting int read", pWatchDogPB->watchDogState); InitParamBlock(myMousePB.pipeRef, &myMousePB.pb); myMousePB.pb.usbBuffer = (Ptr)myMousePB.hidReport; myMousePB.pb.usbReqCount = myMousePB.maxPacketSize; myMousePB.pb.usb.cntl.WIndex = myMousePB.interfaceDescriptor.interfaceNumber; myMousePB.pb.usbCompletion = (USBCompletion)MouseCompletionProc; myMousePB.pb.usbRefcon = kReadInterruptPipe + kCompletionPending; #ifndef DDKBuild myMousePB.pb.usbFlags |= kUSBDebugAwareFlag; #endif myErr = USBIntRead(&myMousePB.pb); if(immediateError(myErr)) { USBExpertFatalError(myMousePB.interfaceRef, kUSBInternalErr, kMouseModuleName": Watchdog - Read Interrupt Pipe (ImmediateError)", myErr); } } pWatchDogPB->watchDogAbortFlag = false; break; } pWatchDogPB->watchDogActivityFlag = false; pWatchDogPB->watchDogAbortFlag = false; if (pWatchDogPB->watchDogState == kCheckForAbort) { USBAbortPipeByReference(pWatchDogPB->pipeRef); } } InitParamBlock( pWatchDogPB->interfaceRef, &pWatchDogPB->pb ); pWatchDogPB->pb.usbBuffer = 0; pWatchDogPB->pb.usbActCount = 0; pWatchDogPB->pb.usbReqCount = delayTime; pWatchDogPB->pb.usbRefcon = 0; pWatchDogPB->pb.usbCompletion = (USBCompletion)WatchDogCompletionProc; USBDelay(&pWatchDogPB->pb); } return; } void MouseCompletionProc(USBPB *pb) { usbMousePBStruct *pMousePB; unsigned char * errstring; USBPipeState pipeState; #if EnableWatchDog OSStatus myErr; #endif pMousePB = (usbMousePBStruct *)(pb); pMousePB->transDepth--; if (pMousePB->transDepth < 0) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth < 0 (completion)", pMousePB->pb.usbRefcon ); } if (pMousePB->transDepth > 1) { USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth > 1 (completion)", pMousePB->pb.usbRefcon ); } pMousePB->pb.usbRefcon |= kCompletionInProgess; // make certain the watchdog routine doesn't race us if( (pMousePB->pb.usbStatus != noErr) && ((pMousePB->pb.usbRefcon & kStageMask) != kGetPortStatus) ) // was there an error? { switch(pMousePB->pb.usbRefcon & kStageMask) // yes, so show where the error occurred { case kSetProtocol: errstring = kMouseModuleName": Error during kSetProtocol"; break; case kSetIdleRequest: errstring = kMouseModuleName": Error during kSetIdleRequest"; break; #if EnableRemoteWakeup case kSetRemoteWakeup: errstring = kMouseModuleName": Error during kSetRemoteWakeup"; break; #endif case kConfigureInterface: errstring = kMouseModuleName": Error during kConfigureInterface"; break; case kFindPipe: errstring = kMouseModuleName": Error during kFindPipe"; break; case kReadInterruptPipe: { errstring = kMouseModuleName": Error during ReadInterruptPipe"; LMSetMouseButtonState(0x80); // release any possibly held-down mouse button break; } default: errstring = kMouseModuleName": Error occurred, but state is unknown"; break; }; pMousePB->pb.usbRefcon &= (kStageMask + kCompletionInProgess); // save the refcon & completion in progress flag pMousePB->pb.usbRefcon |= kRetryTransaction; // set up to retry the transaction pMousePB->retryCount--; // don't put out a fatal error message if an expected abort has occurred if ((pMousePB->pb.usbStatus != kUSBAbortedError) || (watchDogPB.watchDogState != kCheckForAbort)) { USBExpertFatalError(pMousePB->interfaceRef, pMousePB->pb.usbStatus, errstring, (pMousePB->pb.usbRefcon & kStageMask)); } if ((pMousePB->retryCount == 1) && ((pMousePB->pb.usbRefcon & kStageMask) == kSetIdleRequest)) { USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Device doesn't accept SetIdle", pMousePB->interfaceRef); pMousePB->pb.usbRefcon = #if EnableRemoteWakeup kSetRemoteWakeup #else kFindPipe #endif ; pMousePB->pb.usbStatus = noErr; } else { if ((pMousePB->pb.usbStatus == kUSBAbortedError) && (watchDogPB.watchDogState == kCheckForAbort)) { USBExpertStatusLevel(5, pMousePB->interfaceRef, kMouseModuleName": Expected abort has occurred - retry int read", pMousePB->interfaceRef); if (pMousePB->pipeRef) { watchDogPB.watchDogAbortFlag = true; // flag that we had the abort } USBGetPipeStatusByReference(pMousePB->pipeRef, &pipeState); // yes, so what it's state? if (pipeState != kUSBActive) // if it's not active, try to clear it. It might be stalled... { USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe is open and stalled, clearing stall...", pMousePB->interfaceRef); USBClearPipeStallByReference(pMousePB->pipeRef); } } else if ((!pMousePB->retryCount) || (pMousePB->pb.usbStatus == kUSBAbortedError)) // have we exhausted the retries? { // or received an abort? USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe abort or unable to recover from error", pMousePB->interfaceRef); pMousePB->pb.usbRefcon = kReturnFromDriver + kCompletionInProgess; // if so, just exit. pMousePB->intPipeAborted = true; } else // if it didn't abort and there's retries left, then... { if (pMousePB->pipeRef) // check if the pipe is open. { USBGetPipeStatusByReference(pMousePB->pipeRef, &pipeState); // yes, so what it's state? if (pipeState != kUSBActive) // if it's not active, try to clear it. It might be stalled... { USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe is open and stalled, clearing stall...", pMousePB->interfaceRef); USBClearPipeStallByReference(pMousePB->pipeRef); } } if( (pMousePB->pb.usbStatus == kUSBNotRespondingErr) ) { USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": doing port status", pMousePB->interfaceRef); pMousePB->previousState = pMousePB->pb.usbRefcon; pMousePB->pb.usbRefcon = kGetPortStatus; } } } } else { pMousePB->pb.usbRefcon &= ~kRetryTransaction; pMousePB->retryCount = kMouseRetryCount; } if (pMousePB->pb.usbRefcon & kCompletionPending) { pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver); switch(pMousePB->pb.usbRefcon & kStageMask) { case kConfigureInterface: pMousePB->pb.usbRefcon = kSetProtocol + kCompletionInProgess; break; case kSetProtocol: if (kVendorID_AppleComputer == USBToHostWord(pMousePB->deviceDescriptor.vendor) ) { pMousePB->pb.usbRefcon = #if EnableRemoteWakeup kSetRemoteWakeup #else kFindPipe #endif + kCompletionInProgess; } else { pMousePB->pb.usbRefcon = kSetIdleRequest + kCompletionInProgess; } break; case kSetIdleRequest: pMousePB->pb.usbRefcon = #if EnableRemoteWakeup kSetRemoteWakeup #else kFindPipe #endif + kCompletionInProgess; break; #if EnableRemoteWakeup case kSetRemoteWakeup: pMousePB->pb.usbRefcon = kFindPipe; break; #endif case kFindPipe: pMousePB->maxPacketSize = pMousePB->pb.usb.cntl.WValue; pMousePB->pipeRef = pMousePB->pb.usbReference; pMousePB->pb.usbRefcon = kReadInterruptPipe + kCompletionInProgess; USBExpertStatus( watchDogPB.interfaceRef, kMouseModuleName": Initialize watchdog", 0); InitParamBlock( watchDogPB.interfaceRef, &watchDogPB.pb ); watchDogPB.pipeRef = pMousePB->pipeRef; watchDogPB.watchDogState = kDelay10Seconds; watchDogPB.pb.usbBuffer = 0; watchDogPB.pb.usbActCount = 0; watchDogPB.pb.usbReqCount = 20000; // check for mouse activity every twenty seconds watchDogPB.watchDogActivityFlag = false; watchDogPB.pb.usbRefcon = 0; watchDogPB.pb.usbCompletion = (USBCompletion)WatchDogCompletionProc; #if EnableWatchDog myErr = USBDelay(&watchDogPB.pb); if(immediateError(myErr)) { USBExpertFatalError(pb->usbReference, myErr, kMouseModuleName": Setting up watchdog - USBDelay immediate error", 0); } #endif break; case kReadInterruptPipe: watchDogPB.watchDogActivityFlag = true; if (myMousePB.pNotificationRoutine) { (*myMousePB.pNotificationRoutine)(myMousePB.notificationRefcon, pMousePB->pb.usbActCount, (void *)pMousePB->hidReport, myMousePB.interfaceRef); } pMousePB->pb.usbRefcon = kReadInterruptPipe + kCompletionInProgess; break; case kPortStatusDelay: USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": kPortStatusDelay", pMousePB->interfaceRef); pMousePB->pb.usbRefcon = kGetPortStatus; break; case kResetMouseDelay: USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": kPortStatusDelay", pMousePB->interfaceRef); pMousePB->pb.usbRefcon = kResetMouse; break; case kResetMouse: USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": mouse now reset", pMousePB->interfaceRef); // Just give up here, the composite driver should now take care of things. break; case kGetPortStatus: if(pb->usbStatus == kUSBDeviceDisconnected) { USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": port status gives device disconnected, exiting", pMousePB->interfaceRef); pMousePB->pb.usbRefcon = kReturnFromDriver + kCompletionInProgess; // if so, just exit. } else if(pb->usbStatus == kUSBPortDisabled) { USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": port status gives port disabled, resetting", pMousePB->interfaceRef); pMousePB->pb.usbRefcon = kResetMouse; } else if(pb->usbStatus == noErr) { USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": port status transient error, restarting", pMousePB->interfaceRef); //pMousePB->retryCount = kMouseRetryCount; --> done automatically pMousePB->pb.usbRefcon = pMousePB->previousState; } else { USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": port status unknown error", pb->usbStatus); } break; default: USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Transaction completed with bad refcon value", pMousePB->pb.usbRefcon ); pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver + kCompletionInProgess; break; } } pMousePB->pb.usbRefcon &= ~(kCompletionInProgess); if (!(pMousePB->pb.usbRefcon & kReturnFromDriver) && (!pMousePB->driverRemovalPending)) MouseInitiateTransaction(pb); } void InterfaceEntry(UInt32 interfacenum, USBInterfaceDescriptorPtr pInterfaceDescriptor, USBDeviceDescriptorPtr pDeviceDescriptor, USBReference theInterfaceRef) { #pragma unused (interfacenum) static Boolean beenThereDoneThat = false; if(beenThereDoneThat) { USBExpertFatalError(theInterfaceRef, kUSBInternalErr, kMouseModuleName" is not reentrant", 0); return; } beenThereDoneThat = true; // DebugStr("\pIn Mouse Interface Entry routine"); watchDogPB.watchDogState = 0; watchDogPB.watchDogAbortFlag = false; watchDogPB.watchDogActivityFlag = false; watchDogPB.driverRemovalPending = false; watchDogPB.interfaceRef = theInterfaceRef; watchDogPB.pipeRef = nil; watchDogPB.pb.pbLength = sizeof(usbMousePBStruct); myMousePB.driverRemovalPending = false; myMousePB.intPipeAborted = false; myMousePB.deviceDescriptor = *pDeviceDescriptor; myMousePB.interfaceDescriptor = *pInterfaceDescriptor; myMousePB.transDepth = 0; myMousePB.retryCount = kMouseRetryCount; myMousePB.pSHIMInterruptRoutine = nil; myMousePB.pSavedInterruptRoutine = nil; myMousePB.notificationRefcon = 0; myMousePB.pNotificationRoutine = NotifyRegisteredHIDUser; myMousePB.interfaceRef = theInterfaceRef; myMousePB.pipeRef = nil; InitParamBlock(theInterfaceRef, &myMousePB.pb); myMousePB.pb.usbReference = theInterfaceRef; myMousePB.pb.pbLength = sizeof(usbMousePBStruct); myMousePB.pb.usbRefcon = kConfigureInterface; if ((myMousePB.deviceDescriptor.vendor == USB_CONSTANT16(0x046e)) && (myMousePB.deviceDescriptor.product == USB_CONSTANT16(0x6782))) { myMousePB.unitsPerInch = (Fixed)(100<<16); } else { myMousePB.unitsPerInch = (Fixed)(400<<16); } myMousePB.pCursorDeviceInfo = 0; USBHIDControlDevice(kHIDEnableDemoMode,0); MouseInitiateTransaction(&myMousePB.pb); }